/*
 * CallServlet.java
 *
 * Created on November 16, 2006, 10:38 AM
 */
package clicktodial.sip;

import java.io.IOException;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.sip.Address;
import javax.servlet.sip.SipApplicationSession;
import javax.servlet.sip.SipFactory;
import javax.servlet.sip.SipServlet;
import javax.servlet.sip.SipServletRequest;
import javax.servlet.sip.SipServletResponse;
import javax.servlet.sip.SipSession;
import javax.servlet.sip.SipSessionEvent;
import javax.servlet.sip.SipSessionListener;
import clicktodial.web.*;


/**
 * @author jp
 */
public class CallSipServlet extends SipServlet implements SipSessionListener {

    private static final Logger logger =
            Logger.getLogger(CallSipServlet.class.getName());
   
    // inject the SipFactory
    @Resource(mappedName="sip/ClickToDial")
    private SipFactory sf;

    //anuncio por defecto
    private String mediaServer = "sip:you_have@127.0.0.1:5080";
    private static Address destination;
    private static Address origin;



    /**
     * Handle a request to end the call
     * @param request the request to end the call
     */
    @Override
    protected void doBye(SipServletRequest request)
        throws ServletException, IOException
    {
        logger.info("Got bye");
       
        SipSession session = request.getSession();
        SipApplicationSession appSession = sf.createApplicationSession();

        //Actualizamos el anuncio que debemos solicitar
        mediaServer = PlaceCallServlet.dameMediaServer();
       
        // end the linked call
        SipSession linkedSession = (SipSession) session.getAttribute("LinkedSession");
        if (linkedSession != null) {
            String remoteParty = linkedSession.getRemoteParty().toString().substring(1, 1+mediaServer.length());
            String localParty = linkedSession.getLocalParty().toString().substring(1, 1+mediaServer.length());
           
            if(remoteParty.equals(mediaServer) || localParty.equals(mediaServer)){
               
                // create an INVITE request to the first party from the second
                SipServletRequest req = sf.createRequest(appSession, "INVITE",origin,destination);
               
                // store the second party's address in the sip session
                req.getSession().setAttribute("SecondPartyAddress", origin);
       
                SipServletRequest bye = linkedSession.createRequest("BYE");
                logger.info("Originador del Bye: " + linkedSession.getLocalParty().toString().substring(1, 1+mediaServer.length()));
                logger.info("Sending bye to " + linkedSession.getRemoteParty());

                // create an SDP   
                req.send();
                logger.info("Establecemos la llamada con el destino");
               
                // send the BYE request
                bye.send();

            }else{
                // create a BYE request to the linked session
                SipServletRequest bye = linkedSession.createRequest("BYE");
                logger.info("Originador del Bye: " + linkedSession.getLocalParty());
                logger.info("Sending bye to " + linkedSession.getRemoteParty());

                // send the BYE request
                bye.send();
            }
        }
       
        // send an OK for the BYE
        SipServletResponse ok = request.createResponse(SipServletResponse.SC_OK);
        ok.send();
    }
   
    /**
     * Handle a request to cancel a call in progress
     * @param request the request to end the call
     */
    @Override
    protected void doCancel(SipServletRequest request)
        throws ServletException, IOException
    {
        logger.info("Got cancel");
    }
   
   
    /**
     * Handle a success response.  When a call sends an OK message, we
     * complete the call at the bridge.
     * @param resp the success response
     */ 
    @Override
    protected void doSuccessResponse(SipServletResponse resp)
        throws ServletException, IOException
    {
        logger.info("Got OK");
       
        SipSession session = resp.getSession();
               
        // if the response was OK, invite the other party
        if (resp.getStatus() == SipServletResponse.SC_OK) {
           
            // first check if this is a duplicate OK
            Boolean inviteSent = (Boolean) session.getAttribute("InviteSent");
            if (inviteSent != null && inviteSent.booleanValue()) {
                return;
            }
           
            // we are in one of two states here.  Either this OK is from
            // the original invitee, meaning they answered and it is time
            // to ring the second party, or the OK is from the second
            // party, and we should acknowlege the call with both sides
           
           
            // check for the first case, where this OK is from the original
            // invitee
            Address secondPartyAddress =
                    (Address) resp.getSession().getAttribute("SecondPartyAddress"); 
            if (secondPartyAddress != null) {
               
                // invite the second party
                SipServletRequest invite = sf.createRequest(resp.getApplicationSession(),
                        "INVITE", session.getRemoteParty(), secondPartyAddress);
               
                logger.info("Found second party -- sending INVITE to " + secondPartyAddress);
               
                // get the SDP from the OK message
                if (resp.getContentType().equals("application/sdp")) {
                    invite.setContent(resp.getContent(), "application/sdp");
                }       
               
                // link the sessions
                session.setAttribute("LinkedSession", invite.getSession());
                invite.getSession().setAttribute("LinkedSession", session);
               
                // store the ack for the first party -- we'll send it when
                // we get information from the second party
                SipServletRequest ack = resp.createAck();
                invite.getSession().setAttribute("FirstPartyAck", ack);
               
                // send the invite
                invite.send();
               
                // prevent duplicates
                session.setAttribute("InviteSent", Boolean.TRUE);
            } else {
                logger.info("Got OK from second party -- sending ACK");
               
                // send acks
                SipServletRequest secondPartyAck = resp.createAck();
                SipServletRequest firstPartyAck =
                        (SipServletRequest) resp.getSession().getAttribute("FirstPartyAck");
           
                // get the SDP from the second party's OK message
                if (resp.getContentType().equals("application/sdp")) {
                    firstPartyAck.setContent(resp.getContent(), "application/sdp");
                    //secondPartyAck.setContent(resp.getContent(), "application/sdp");
                }
               
                firstPartyAck.send();
                secondPartyAck.send();
            }
        }
    }
   
    /**
     * Handle an error response.  Close the relevant call at the bridge.
     * @param resp the error response
     */
    @Override
    protected void doErrorResponse(SipServletResponse resp)
        throws ServletException, IOException
    {
        logger.info("Got error");
       
        // cancel the call
        resp.getSession().invalidate();
    }
  
    ////////
    // SipSessionListener interface
   
    /**
     * Called when a session is created.  Ignore.
     * @param sse the event
     */
    public void sessionCreated(SipSessionEvent sse) {
        logger.info("Session created");
    }

    /**
     * Called when a session is removed.  Remove any call data associated
     * with the given session.
     * @param sse the event
     */
    public void sessionDestroyed(SipSessionEvent sse) {
        logger.info("Session destroyed");
    }
   
    public static void setDestination(Address to){
        destination = to;  
        logger.info("Establecido usuario llamado: " + to.toString());
    }
    public static void setOrigin(Address from){
        origin = from;  
        logger.info("Establecido originador de la llamada: " + from.toString());
    }
}
